/******************************************************************************
 *
 *  socket_tcp_fork_server.c
 *
 *  Created on: 2012-3-11
 *      Author: Michael
 *       Email: zhongchao.ustc@gmail.com
 *
 *  Copyright (c) Michael Chao Zhong
 *
 *	Compile:
 *		gcc -o server socket_tcp_fork_server.c
 *
 *	Run:
 *		./server 19877
 *		# 19877 is the port indicated for listening connection from clients
 *
 *****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
	int server_port = atoi(argv[1]);

	// Create socket
	int socket_fd = socket(AF_INET, SOCK_STREAM, 0);

	// Initialize the server address
	struct sockaddr_in server_addr;
	bzero((char *) &server_addr, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = INADDR_ANY;
	server_addr.sin_port = htons(server_port);

	// Bind
	bind(socket_fd, (struct sockaddr *) &server_addr, sizeof(server_addr));

	// Listen
	listen(socket_fd, 5);

	// Start
	while (1)
	{
		// Accept
		struct sockaddr_in client_addr;
		socklen_t client_addr_length = sizeof(client_addr);
		int socket_to_client = accept(socket_fd,
				(struct sockaddr *) &client_addr, &client_addr_length);
		
		// Fork
		pid_t pid = fork();

		// Fork - Error
		if (pid < 0) {
			perror("Forking fails. Exit...");
			exit(1);
		}
		// Fork - Child process
		else if (pid == 0) {
			
			// Child process closes socket_fd
			close(socket_fd);
			
			// Child process reads data
			char buffer[1024];
			bzero(buffer, sizeof(buffer));		
			read(socket_to_client, buffer, sizeof(buffer) - 1);
			printf("The message received: %s\n", buffer);
			
			// Child writes data
			const char *data = "I got your message.";
			write(socket_to_client, data, strlen(data));

			// Child process halts
			exit(0);
		}
		// Fork - Parent process
		else {

			// Parent process closes socket_to_client
			close(socket_to_client);
		}
	}

	close(socket_fd);

	return 0;
}
